package com.bupt.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bupt.enums.ResultCode;
import com.bupt.exceptions.BusinessException;
import com.bupt.film.client.FilmInfoClient;
import com.bupt.film.entity.Film;
import com.bupt.film.entity.Hall;
import com.bupt.order.dto.OrderDto;
import com.bupt.order.entity.Order;
import com.bupt.order.mapper.OrderMapper;
import com.bupt.order.service.OrderService;
import com.bupt.user.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpSession;
import java.util.*;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {


    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private FilmInfoClient filmInfoClient;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private HttpSession httpSession;

    private final int TICKETS_LIMIT = 4;
    private final String ORDER_GLOBAL_ID_KEY = "order.globalId";



    @Override
    public List<Order> getAllOrders() {
//        throw new BusinessException(ResultCode.FILM_NOT_FOUND);
        return orderMapper.selectAll();
    }

    @Override
    public List<Order> getOrdersByUserId(String userId) {
        Order order = new Order();
        order.setUserId(userId);
        return orderMapper.select(order);
    }

    @Override
    public List<Order> getOrdersByModel(Order order) {
        return orderMapper.select(order);
    }

    @Override
    public Map<String, Object> getOrdersCountByModel(Order order) {
        int count = orderMapper.selectCount(order);
        Map<String, Object> map = new HashMap<>();
        map.put("ordersCount", count);
        return map;
    }

    @Override
    public Map<String, Object> getTicketsSoldNumByModel(Order order) {
        List<Order> matchingOrders = getOrdersByModel(order);
        int ticketsSold = 0;
        for (Order itemOrder : matchingOrders) {
            ticketsSold+=itemOrder.getTicketsNum();
        }
        Map<String, Object> map = new HashMap<>();
        map.put("ticketsSold", ticketsSold);
        return map;
    }


    /*
    {
  "filmDate": "2021-08-10",
  "filmId": "film_1",
  "hallId": "hall_1",
  "ticketsNum": 1,
  "timePeriod": "09:00",
  "userId": "2020111111"
}
     */
    @Override
    public void createOrder(OrderDto orderDto) {
        Order order = new Order();
        BeanUtils.copyProperties(orderDto, order);

        //判断电影信息和影厅信息是否有效
        Film filmInfo = filmInfoClient.getOneFilmInfo(order.getFilmId());
        Hall hallInfo = filmInfoClient.getOneHallInfo(order.getHallId());
        if (filmInfo == null) {
            throw new BusinessException(ResultCode.FILM_NOT_FOUND);
        }
        if (hallInfo == null) {
            throw new BusinessException(ResultCode.HALL_NOT_FOUND);
        }

        //判断电影放映时间是否在放映期内
        Date orderFilmDate = order.getFilmDate();
        Date filmStartDate = filmInfo.getStartTime();
        Date filmEndDate = filmInfo.getEndTime();
        if (orderFilmDate.getTime() < filmStartDate.getTime() || orderFilmDate.getTime() > filmEndDate.getTime()) {
            throw new BusinessException(ResultCode.NOT_IN_FILM_SHOWRANGE);
        }

        //判断影厅中是否包含这个电影
        String filmIdsStr = hallInfo.getFilmIds();
        String[] filmIds = JSON.parseObject(filmIdsStr, String[].class);
        if (!Arrays.asList(filmIds).contains(filmInfo.getFilmId())) {
            throw new BusinessException(ResultCode.FILM_NOT_SHOW_IN_HALL);
        }

        //判断电影时段是否有效
        String filmTimePeriodsStr = hallInfo.getFilmTimePeriods();
        String[] filmTimePeriods = JSON.parseObject(filmTimePeriodsStr, String[].class);
        if (!Arrays.asList(filmTimePeriods).contains(order.getTimePeriod())) {
            throw new BusinessException(ResultCode.TIME_PERIOD_NOT_FOUND);
        }

        //判断订单票数是否超过上限
        if (order.getTicketsNum() > TICKETS_LIMIT) {
            throw new BusinessException(ResultCode.TICKETS_EXCEED_LIMIT);
        }

        //判断用户信息是否存在
        if (order.getUserId() == null) {
            throw new BusinessException(ResultCode.PARAM_IS_INVALID);
        }

        //判断用户信息是否和session中登录的一致
        String sessionId = httpSession.getId();
        System.out.println(sessionId);
        User sessionUser = (User) httpSession.getAttribute(httpSession.getId());
        //获取不到就尝试10次
//        try {
//            Thread.sleep(10000L);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        int count = 0;
        while (sessionUser == null) {
            sessionUser = (User) httpSession.getAttribute(httpSession.getId());
            count++;
            if (count >= 9) {
                throw new BusinessException(ResultCode.SYSTEM_BUSY);
            }
        }
        if (!sessionUser.getUserId().equals(order.getUserId())) {
            throw new BusinessException(ResultCode.USER_SESSION_NOT_MATCH);
        }

        //获取场次剩余票数
        //先获取对应场次的订单数量，随后用场次的票数减去这个订单数量所有ticket_num的总和
        Order o = new Order();
        o.setHallId(order.getHallId());
        o.setFilmDate(order.getFilmDate());
        o.setTimePeriod(order.getTimePeriod());
        Map<String, Object> ticketsSoldMap = getTicketsSoldNumByModel(o);
        int ticketsSold = (int) ticketsSoldMap.get("ticketsSold");
        int seatNum = hallInfo.getSeatNum();
        int remainingTickets = seatNum - ticketsSold;
        log.debug("对应场次一共{}张票，已经售出{}张票，剩余{}张票", seatNum, ticketsSold, remainingTickets);
        //判断剩余票数是否足够
        if (remainingTickets < order.getTicketsNum()) {
            throw new BusinessException(ResultCode.NOT_ENOUGH_TICKETS);
        }

        //如果票数足够就售出电影票
        //创建订单时间
        long currentTimeMillis = System.currentTimeMillis();
        Date currentDate = new Date(currentTimeMillis);
        log.debug("订单时间是：{}", currentDate);
        order.setCreateTime(currentDate);

        //生成订单号
        Long increment = redisTemplate.opsForValue().increment(ORDER_GLOBAL_ID_KEY, 1);
        String orderGlobalId = "order_" + increment;

        order.setOrderId(orderGlobalId);
        order.setFilmName(filmInfo.getName());

        orderMapper.insert(order);
    }

    @Override
    public String getUserSessionTest() {
        String id = httpSession.getId();
        System.out.println(id);
        User attribute = (User) httpSession.getAttribute(id);
        if (attribute == null) {
            return null;
        }
        return attribute.getUserId();
    }
}
